from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text  # 用于sql安全
from flask_migrate import Migrate

app = Flask(__name__)
# MYSQL所在的主机名
HOSTNAME = "127.0.0.1"
# mysql监听的端口号
PORT = "3306"
# 连接mysql的用户名
USERNAME = "root"
# 连接mysql的密码
PASSWORD = ""
# MYSQL上创建的数据库名
DATABASE = "database_learn"
# app.config的配置
app.config[
    "SQLALCHEMY_DATABASE_URI"] = f"mysql+pymysql://{USERNAME}:{PASSWORD}@{HOSTNAME}:{PORT}/{DATABASE}?charset=utf8mb4"

# 1、在app.config配置中设置好数据库的信息
# 2、然后使用SQLAlchemy(app)创建一个db对象
# 3、SQLAlchemy会自动读取app.config中连接数据库的信息
db = SQLAlchemy(app)

migrate = Migrate(app, db)


# 在终端terminal中执行ORM映射成表的三步
# 1、初始化（只做一次）：flask db init
# 2、生成迁移脚本（可识别ORM模型的改变）：flask db migrate
# 3、运行迁移脚本（并同步到数据库中）：flask db upgrade

# 一个类就是一个mysql表
class User(db.Model):
    __tablename__ = "user"  # 表名，不写默认为类名
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    username = db.Column(db.String(100), nullable=False)
    password = db.Column(db.String(200), nullable=False)

    # 添加外键，需要双向绑定，也就是article与user表都需要写下面这个标记语句（推荐使用这种双向标记语句）
    # articles = db.relationship("article", back_populates="author")

    # user = User(username="张三", password="111111")  # 等于insert into user(username,password) values ("张三", ”111111“)


class Article(db.Model):
    __tablename__ = "article"
    id = db.Column(db.Integer, primary_key=True, autoincrement=True)
    title = db.Column(db.String(100), nullable=False)
    content = db.Column(db.Text, nullable=False)

    # 添加作者外键，author_id类型必须与外键user.id保持一致
    author_id = db.Column(db.Integer, db.ForeignKey("user.id"))
    # 需要双向绑定，也就是article与user表都需要写下面这个标记语句 （推荐使用这种双向标记语句）
    # author = db.relationship("User", back_populates="articles")
    # 只需要article表绑定就可以，back_ref会自动给User模型添加一个articles属性，用来获取文章列表
    author = db.relationship("User", backref="articles")


# article = Article(title="Flask学习", content="flaskXXXXXX", author_id="")
# article.author_id = user.id
# user = User.query.get(article.author_id) 这种方式不够面向对象
# article.author = User.query_get(article.author_id)
# print(article.author)
# article.author代码执行逻辑：先查找article表的author属性，并找到与之相关联的User表，然后通过author_id在user表中查找相关数据后，复制给author;back_populates="articles"表示反向引用，让user.articles能使用

with app.app_context():
    db.create_all()  # 把所有的表都映射到数据库中


@app.route("/article/add")
def article_add():
    # 把两篇文章绑定给同一个作者
    article1 = Article(title="flask学习", content="flask从入门到精通")
    article1.author = User.query.get(2)

    article2 = Article(title="Django学习", content="Django从入门到精通")
    article2.author = User.query.get(2)
    # 添加多个到session中
    db.session.add_all([article1, article2])
    # 同步数据到数据库中
    db.session.commit()
    return "文章添加成功"


@app.route("/article/query")
def artilcle_query():
    # user = User.query.get(2) 方法已过时，会报错、
    # 新查询方法，查询同一作者下的多篇文章
    user = db.session.get(User, 2)
    for article in user.articles:
        print(article.title)
    return "文章查询成功"


@app.route("/article/update")
def article_update():
    Article.author = "flask学习2"
    db.session.commit()
    return "文章已更新"


@app.route("/user/add")
def user_add():
    # 1、创建orm对象
    user = User(username="张三", password="123456")
    # 2、将orm对象提交到db.session中
    db.session.add(user)
    # 3、将db.session中的改变提交同步到数据库中
    db.session.commit()
    return "用户创建成功"


@app.route("/user/query")
def query_user():
    # 1、查找一条数据：get查找：根据主键查找
    user = User.query.get(1)  # 相当于select * form user where id=1
    print(f"{user.id}:{user.username}--{user.password}")
    # 2、查找多条数据：filter_by查找
    # Query类数组
    users = User.query.filter_by(username="张三")
    for user in users:
        print(user.username)
    return "数据查找成功"


@app.route("/user/update")
def update_user():
    user = User.query.filter_by(username="张三")
    user.password = "222222"
    db.session.commit()
    return "修改数据成功"


@app.route("/user/delete")
def delete_user():
    # 1、查找
    user = User.query.get(1)
    # 2、从db.session中删除
    db.session.delete(user)
    # 3、将db.session中的修改，同步到数据库中
    db.session.commit()
    return "数据删除成功"


if __name__ == "__main__":
    app.run(debug=True, host="0.0.0.0", port=5000)

# # 测试数据库连接是否正常
# # with app.app_context():
# #     with db.engine.connect() as conn:
# #         # text()函数用于sql安全，防止sql注入，支持参数化查询，用 :param 占位符 + 参数传值，绝不拼接用户输入
# #         rs = conn.execute(text("select 1"))
# #         print(rs.fetchone())
